#! /usr/bin/env python
# -*- coding: utf-8 -*-

import re
import os
import time
import random
import traceback
import hashlib

import FileHostProtoType

class bsitem(FileHostProtoType.HostItem):
    pass

class bitshare(FileHostProtoType.FileHostProcess):
    HOSTNAME = "Bitshare"
    HOST_URL = "http://bitshare.com/"
    COOKIE_CHECK_URL = HOST_URL
    LOGIN_URL = "http://bitshare.com/login.html"
    API_URL = "http://bitshare.com/ajax_responder.html"
    
    def __init__(self,user,pwd):
        FileHostProtoType.FileHostProcess.__init__(self)
        self._opener = None
        self._cj = None
        self._user = user
        self._pwd = pwd
        self.islogin = False
        self.logtype = 'poster'
    
    def login(self):
        '''
        login to Bitshare
        '''
        if self.islogin == True:
            return True
        self.fherr.write('login to %s %s/%s...' % (self.HOSTNAME, self._user,'*'*len(self._pwd)))
        loginData = {'user' : self._user, \
                     'password' : self._pwd, \
                     'submit' : 'Login' }
        self.loginFileHost(self.LOGIN_URL, loginData)
        #access index page
        indexpage = self.post_request(self.COOKIE_CHECK_URL)
        if self._user in indexpage:
            self.fherr.write("User %s logined." % self._user)
            self.islogin = True
            return True
        self.fherr.write("User %s Failed to Login BitShare." % self._user)
        return False
    
    def getFileList(self):
        folder_list = self.getFolderList()
        root = bsitem('root','folder','0','')
        folder_list.append(root)
        files = []
        self.fherr.write("Listing files...")
        for f in folder_list:
            files.extend(self.getFilesFromFolder(f))
        files.sort()
        return files

    def getFileFromRoot(self):
        root_folder = bsitem('root','folder','0','')
        return self.getFilesFromFolder(root_folder)
    
    def getFilesFromFolder(self, folder):
        file_list = []
        self.fherr.write('Get files from folder %s' % folder.name)
        page = 0
        while True:
            data = {
                    'action' : 'getfilelist',
                    'filter_downloads' : '',
                    'filter_filetype' : '',
                    'filter_from' : '',
                    'filter_keyword' : '',
                    'filter_on' : 'false',
                    'filter_size' : '',
                    'filter_to' : '',
                    'mainfolder' : folder.id,
                    'orderby' : '',
                    'ordertype' : '',
                    'page' : page,
                    'pagesize' : '10000',
                    'section' : 'myfiles',
                    }
            response = self.post_request(self.API_URL, data)
            re_file_info = re.compile('<label id="filehash_(?P<id>\d+)">(?P<hash>[0-9a-zA-Z]+)</label>.*?<label id="filename_\d+">(?P<name>.*?)</label>', re.I|re.S)
            result_iter = re_file_info.finditer(response)
            has_new_file = False
            for r in result_iter:
                has_new_file = True
                name = r.group('name')
                id = r.group('id')
                hash = r.group('hash')
                item = bsitem(name, 'file', id, 'http://bitshare.com/files/{}/{}.html'.format(hash, name))
                file_list.append(item)
            if not has_new_file:
                break
            page += 1
        return file_list
    
    def getFolderList(self):   
        data = {'action':'getfolderlist',
                'section':'myfiles'
                }
        response = self.post_request(self.API_URL, data)
        # hard to rebulit parent-child list, so omit.
        reFolder = re.compile('id="folder_(?P<id>\d+)".*?folderhash="(?P<hash>[0-9a-zA-Z]+)".*?<span.*?>(?P<name>.*?)</span>')
        matchResult = reFolder.finditer(response)
        foundFolders = []
        for r in matchResult:
            name = r.group('name')
            id = r.group('id')
            link = 'http://bitshare.com/?d=' + r.group('hash')
            item = bsitem(name, 'folder', id, link)
            foundFolders.append(item)
        foundFolders.sort()
        if not foundFolders:
            self.fherr.write(response)
            self.fherr.write('There is no folders.')
        return foundFolders 
    
    def find(self, filenames=[], filelist=None):
        '''
        open the filelist page according to opener with cookies
        '''
        found = []
        if filelist is None:
            filelist = self.getFileList()        
        filelistlower = [fl.name.lower() for fl in filelist]
        todel = []
        for fl in filenames:
            try:
                index = filelistlower.index(os.path.basename(fl).lower())
                found.append(filelist[index])
                todel.append(fl)
            except:
                continue
        for d in todel:
            filenames.remove(d)
        found.sort()
        return found

    def findFolder(self, foldername):        
        folders = self.getFolderList()
        for f in folders:
            if foldername == f.name:
                return f
        return None

    def createFolder(self, newfolder):
        foundfolder = self.findFolder(newfolder)
        if foundfolder is None:
            #bitshare no longer allow user to create subdir 
            return self.__newFolder(newfolder)
        self.fherr.write("Folder %s exsits." % newfolder)
        return foundfolder

    def __newFolder(self, newfolder, parentfolder=None):
        '''
        newfolder : without any '/',just a standard folder name
        '''
        data =[]
        pid = '0'
        if parentfolder is not None:
            pid = parentfolder.id
        data.append(('action', 'newfolder'))
        data.append(('foldername', newfolder))
        data.append(('mainfolder', pid))  
        data.append(('section', 'myfiles'))
        self.fherr.write("Creating folder %s ..." % newfolder)
        retry = 10
        while(retry > 0):            
            response = self.post_request(self.API_URL, data, retry=1)
            new_folder_id =  response[response.find(':')+1:]
            time.sleep(10)
            newItem = self.findFolder(newfolder)
            if newItem is not None and new_folder_id == newItem.id:
                return newItem
            retry -= 1
        return None
    
    def moveto(self, items, destFolder):
        if len(items) == 0:
            return
        for i in items:
            data = {'action':'movefile',
                    'file':i.id,
                    'mainfolder': destFolder.id,
                    'section':'myfiles'}
                    
            response = self.post_request(self.API_URL, data)
            if 'MOVED' in response:
                self.fherr.write("%s has been moved to %s." % (i.name, destFolder.name))
            else:
                self.fherr.write("Fail to move %s to %s" % (i.name, destFolder.name))
    
    def upload_web(self, file, progressLog=None, other_args=None, send_range=None):
        return self.upload_web_local(file, progressLog, other_args, send_range)
    
    def upload_web_local(self, file, progressLog=None, other_args=None, send_range=None):
        #upload page           
        uploadpage = self.post_request(self.HOST_URL)
        
        uploadlink = self.get_upload_key(uploadpage, "return StartUpload();", 1)
        randomnumber = self.get_random()        
        uploadlink = uploadlink + '?X-Progress-ID=undefined' + randomnumber.lower()
        
        progress_key = self.get_upload_key(uploadpage, 'name="APC_UPLOAD_PROGRESS"', -2)
        usergroup_key = self.get_upload_key(uploadpage, 'name="APC_UPLOAD_USERGROUP"', -2)
        identifier = self.get_upload_key(uploadpage, 'name="UPLOAD_IDENTIFIER"', -2)
        
        filesize = os.path.getsize(file)
        filename = self.rename_func(file)
        start_point = 0
        info = "Uploading...%s" % file
        if send_range is not None:
            #range is a 3-tuple, <start, end, number>
            filesize = send_range[1] - send_range[0] + 1
            filename += ".%03d" % send_range[2]
            start_point = send_range[0]
            info += ".%03d" % send_range[2]
            info += "Filesize: %s" % filesize
            
        fileobj = open(file, 'rb')
        fileobj.seek(start_point)  
        data = {}
        data["APC_UPLOAD_PROGRESS"] = progress_key
        data['APC_UPLOAD_USERGROUP'] = usergroup_key
        data['UPLOAD_IDENTIFIER'] = identifier
        data['file[1]'] = fileobj
        
        self.fherr.write(info)  
        
        callback = None
        if progressLog is not None:
            callback = progressLog.write
        resultMsg = self.post_request(uploadlink, \
                                   data, \
                                   retry=1, \
                                   cb=callback,\
                                   setfilename=filename,
                                   setfilesize=filesize)
        if resultMsg is None:
            self.fherr.write("UploadTask(%s) was Stop by user." % file)
            return
        try:
            #get short link
            shortlink = re.search('value="(?P<link>http://bitshare.com/\?f=[0-9a-zA-z]+)"', resultMsg).\
                    group('link')
            link = re.search('value="(?P<link>http://bitshare.com/files/[0-9a-zA-z]+/.*?html)"', resultMsg).\
                    group('link')
            item = bsitem(os.path.basename(file), 'file', '', link, filename)

            self.fherr.write(item.format())        
            self.newupload.append(item)
            return item
        except:
            self.fherr.write('****************')
            self.fherr.write(resultMsg)
            self.fherr.write('****************')
            self.fherr.write('Failed to get link.')
            self.fherr.write(traceback.format_exc())
            return

    def upload_to_ftp(self, file, progressLog=None, other_args=None):
        raise NotImplementedError("FTP mode has not implement.")
        
if __name__ == "__main__":
    pass
